package com.example.zlpermissionservice.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.zlpermissionservice.common.constant.CommonConstant;
import com.example.zlpermissionservice.common.exception.BaseException;
import com.example.zlpermissionservice.common.exception.NumProcessing;
import com.example.zlpermissionservice.dto.request.ResourceReqDTO;
import com.example.zlpermissionservice.dto.response.*;
import com.example.zlpermissionservice.mapper.ResourceMapper;
import com.example.zlpermissionservice.mapper.RoleResourceMapper;
import com.example.zlpermissionservice.service.IResourceService;
import com.example.zlpermissionservice.service.IRoleService;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import com.example.zlpermissionservice.entity.Resource;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author zhenliu（孙凌岳）
 * @Description TODO
 * @Date 2025/6/15 19:31
 * @Version 1.0
 */
@Service
@Slf4j
public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, Resource> implements IResourceService {
    @javax.annotation.Resource
    private ResourceMapper resourceMapper;

    @javax.annotation.Resource
    private IRoleService roleService;

    @javax.annotation.Resource
    private RoleResourceMapper roleResourceMapper;

    /**
     * 修改资源
     * @param resourceReqDTO
     * @return
     */
    @Override
    public Boolean updateResource(ResourceReqDTO resourceReqDTO) {
        //转换
        Resource resource = BeanUtil.toBean(resourceReqDTO, Resource.class);
        resource.setCreateTime(LocalDateTime.now());
        if (resource.getDataState().equals("1")) {
            if (hasChildByMenuId(resource.getResourceNo())) {
                throw new RuntimeException("存在子菜单,不允许禁用");
            }
            if (checkMenuExistRole(resource.getResourceNo())) {
                throw new RuntimeException("菜单已分配,不允许禁用");
            }
        }
        boolean save = this.saveOrUpdate(resource);
        if (!save) {
            throw new RuntimeException("修改资源信息出错");
        }
        return true;
    }

    /**
     * 是否存在菜单子节点
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    public boolean hasChildByMenuId(String menuId) {
        int result = resourceMapper.hasChildByMenuId(menuId);
        return result > 0 ? true : false;
    }

    /**
     * 查询菜单使用数量
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    public boolean checkMenuExistRole(String menuId) {
        int result = roleResourceMapper.checkMenuExistRole(menuId);
        return result > 0 ? true : false;
    }

    /**
     * 角色对应资源
     * @param roleIds 角色s
     * @return
     */
    @Override
    public List<ResourceResDTO> findResourceResDTOListInRoleId(List<Long> roleIds) {
        return resourceMapper.findResourceResDTOListInRoleId(roleIds);
    }

    /**
     * 根据角色id获取角色对应资源
     * @param userId 角色id
     * @return
     */
    @Override
    public List<ResourceResDTO> findResourceResDTOListByUserId(Long userId) {
        return resourceMapper.findResourceResDTOListByUserId(userId);
    }

    /**
     * 查询当前登录人的菜单
     * @return
     */
    @Override
    public List<MenuResDTO> menus(Long userId) {
        //查询对应角色
        List<RoleResDTO> roleVoList = roleService.findRoleResDTOListInUserId(Arrays.asList(userId));
        List<Long> roleIds = roleVoList.stream().map(RoleResDTO::getId).collect(Collectors.toList());
        if (CollUtil.isEmpty(roleIds)) {
            throw new BaseException("请为用户分配角色和菜单");
        }
        //查询角色对应的所有的菜单数据
        List<ResourceResDTO> resources = resourceMapper.findResourceResDTOListInRoleId(roleIds);

        List<MenuResDTO> list = new ArrayList<>();

        recursionMenuResDTO(list, resources);
        return list;

    }

    /**
     * 查询当前登录人的按钮
     * @return
     */
    @Override
    public List<MenuResDTO> buttons(Long userId) {
        //查询对应角色
        List<RoleResDTO> roleVoList = roleService.findRoleResDTOListInUserId(Arrays.asList(userId));
        List<Long> roleIds = roleVoList.stream().map(RoleResDTO::getId).collect(Collectors.toList());
        if (CollUtil.isEmpty(roleIds)) {
            throw new BaseException("请为用户分配角色和菜单");
        }
        //全部的菜单，包含了菜单和按钮
        List<ResourceResDTO> resources = resourceMapper.findButtonResDTOListInRoleId(roleIds);

        List<MenuResDTO> list = new ArrayList<>();
        recursionButtonVo(list, resources);
        return list;
    }

    /**
     * 多条件查询资源列表
     * @param resourceReqDTO
     * @return
     */
    @Override
    public List<ResourceResDTO> findResourceList(ResourceReqDTO resourceReqDTO) {
        List<Resource> resourceList = lambdaQuery().like(resourceReqDTO.getResourceName() != null && !resourceReqDTO.getResourceName().isEmpty(),
                        Resource::getResourceName, resourceReqDTO.getResourceName())
                .likeRight(resourceReqDTO.getRequestPath() != null && !resourceReqDTO.getRequestPath().isEmpty(),
                        Resource::getRequestPath, resourceReqDTO.getRequestPath())
                .eq(resourceReqDTO.getLabel() != null && !resourceReqDTO.getLabel().isEmpty(),
                        Resource::getLabel, resourceReqDTO.getLabel())
                .eq(resourceReqDTO.getResourceType() != null && !resourceReqDTO.getResourceType().isEmpty(),
                        Resource::getResourceType, resourceReqDTO.getResourceType())
                .likeRight(resourceReqDTO.getParentResourceNo() != null && !resourceReqDTO.getParentResourceNo().isEmpty(),
                        Resource::getParentResourceNo, resourceReqDTO.getParentResourceNo())
                .eq(resourceReqDTO.getDataState() != null && !resourceReqDTO.getDataState().isEmpty(),
                        Resource::getDataState, resourceReqDTO.getDataState())
                .orderByAsc(Resource::getSortNo)
                .list();
        return BeanUtil.copyToList(resourceList, ResourceResDTO.class);
    }

    /**
     * 获取树形结构资源
     * @param resourceReqDTO
     * @return
     */
    @Override
    public TreeResDTO resourceTreeVo(ResourceReqDTO resourceReqDTO) {
        //指定节点查询树形结构
        ResourceReqDTO resourceDto1 = resourceReqDTO.builder()
                .dataState(CommonConstant.DATA_STATE_0)
                .parentResourceNo(NumProcessing.processString(CommonConstant.ROOT_PARENT_ID))
                .build();
        //数据库查询资源数据
        List<Resource> resourceList = lambdaQuery()
                .like(StrUtil.isNotBlank(resourceDto1.getResourceName()), Resource::getResourceName, resourceDto1.getResourceName())
                .likeRight(StrUtil.isNotBlank(resourceDto1.getRequestPath()), Resource::getRequestPath, resourceDto1.getRequestPath())
                .eq(StrUtil.isNotBlank(resourceDto1.getLabel()), Resource::getLabel, resourceDto1.getLabel())
                .eq(StrUtil.isNotBlank(resourceDto1.getResourceType()), Resource::getResourceType, resourceDto1.getResourceType())
                .likeRight(StrUtil.isNotBlank(resourceDto1.getParentResourceNo()), Resource::getParentResourceNo, resourceDto1.getParentResourceNo())
                .eq(StrUtil.isNotBlank(resourceDto1.getDataState()), Resource::getDataState, resourceDto1.getDataState())
                .orderByAsc(Resource::getSortNo)
                .list();

        if (CollUtil.isEmpty(resourceList)) {
            throw new RuntimeException("资源信息为定义！");
        }

        //返回的树形集合
        List<TreeItemResDTO> treeItemResDTOList = new ArrayList<>();

        //找根节点
        Resource rootResource = new Resource();
        rootResource.setResourceNo(CommonConstant.ROOT_PARENT_ID);
        rootResource.setResourceName("权限管理系统");
        //构建树形结构
        recursionTreeItem(treeItemResDTOList, rootResource, resourceList);
        return TreeResDTO.builder()
                .items(treeItemResDTOList)
                .build();
    }

    /**
     * 删除资源
     * @param menuId
     * @return
     */
    @Override
    public Boolean deleteMenuById(String menuId) {
        if (hasChildByMenuId(menuId)) {
            throw new RuntimeException("存在子菜单,不允许删除");
        }
        if (checkMenuExistRole(menuId)) {
            throw new RuntimeException("菜单已分配,不允许删除");
        }
        boolean remove = lambdaUpdate()
                .eq(Resource::getResourceNo, menuId)
                .remove();
        log.info("******删除返回值" + remove);
        return remove;
    }

    /**
     * 递归查询树结构
     * @param treeItemVoList
     * @param ResourceRoot
     * @param resourceList
     */
    private void recursionTreeItem(List<TreeItemResDTO> treeItemVoList, Resource ResourceRoot, List<Resource> resourceList) {
        TreeItemResDTO treeItem = TreeItemResDTO.builder()
                .id(ResourceRoot.getResourceNo())
                .label(ResourceRoot.getResourceName())
                .build();
        //获得当前资源下子资源
        List<Resource> childrenResource = resourceList.stream()
                .filter(n -> n.getParentResourceNo().equals(ResourceRoot.getResourceNo()) && n.getResourceType().equals(CommonConstant.MENU))
                .collect(Collectors.toList());
        if (!CollUtil.isEmpty(childrenResource)) {
            List<TreeItemResDTO> listChildren = Lists.newArrayList();

            childrenResource.forEach(resource -> {
                this.recursionTreeItem(listChildren, resource, resourceList);
            });
            treeItem.setChildren(listChildren);
        }

        treeItemVoList.add(treeItem);
    }

    /**
     *  递归按钮
     */
    public List<MenuResDTO> recursionButtonVo(List<MenuResDTO> list, List<ResourceResDTO> resources) {
        for (ResourceResDTO resource : resources) {
            if (resource.getParentResourceNo().equals(CommonConstant.ROOT_PARENT_ID)) {
                MenuResDTO menuResDTO = new MenuResDTO();
                menuResDTO.setPath(resource.getRequestPath());
                menuResDTO.setName(resource.getResourceName());
                menuResDTO.setChildren(getAllChildrens(resource, resources));
                list.add(menuResDTO);
            }
        }
        return list;
    }

    /**
     * 递归获取菜单和按钮
     *
     * @param resource
     * @param resources
     * @return
     */
    private List<MenuResDTO> getAllChildrens(ResourceResDTO resource, List<ResourceResDTO> resources) {

        List<MenuResDTO> childrenList = Lists.newArrayList();
        for (ResourceResDTO resourceResDTO : resources) {
            if (resourceResDTO.getParentResourceNo().equals(resource.getResourceNo())) {
                MenuResDTO menuResDTO = new MenuResDTO();
                menuResDTO.setPath(resourceResDTO.getRequestPath());
                menuResDTO.setName(resourceResDTO.getResourceName());
                menuResDTO.setChildren(getAllChildrens(resourceResDTO, resources));
                childrenList.add(menuResDTO);
            }
        }

        return childrenList;
    }

    /**
     *  递归菜单
     */
    public List<MenuResDTO> recursionMenuResDTO(List<MenuResDTO> list, List<ResourceResDTO> resources) {
        for (ResourceResDTO resource : resources) {
            if (resource.getParentResourceNo().equals(CommonConstant.ROOT_PARENT_ID)) {
                MenuResDTO menuResDTO = new MenuResDTO();
                menuResDTO.setPath(resource.getRequestPath());
                menuResDTO.setName(resource.getResourceName());
                menuResDTO.setPath("/" + resource.getRequestPath());
                menuResDTO.setComponent(CommonConstant.COMPONENT_LAYOUT);

                MenuMetaResDTO menuMetaResDTO = MenuMetaResDTO.builder()
                        .icon(resource.getIcon())
                        .title(resource.getResourceName())
                        .build();
                menuResDTO.setMeta(menuMetaResDTO);
                menuResDTO.setRedirect("/" + resource.getResourceName());

                menuResDTO.setChildren(getChildrens(resource, resources, resource.getRequestPath()));
                list.add(menuResDTO);
            }
        }
        return list;
    }

    /**
     * 递归获取菜单和按钮
     *
     * @param resource
     * @param resources
     * @return
     */
    private List<MenuResDTO> getChildrens(ResourceResDTO resource, List<ResourceResDTO> resources, String component) {

        List<MenuResDTO> childrenList = Lists.newArrayList();
        for (ResourceResDTO resourceResDTO : resources) {
            if (resourceResDTO.getParentResourceNo().equals(resource.getResourceNo())) {
                MenuResDTO menuResDTO = new MenuResDTO();
                menuResDTO.setPath(resourceResDTO.getRequestPath());
                menuResDTO.setName(resourceResDTO.getResourceName());
                menuResDTO.setPath(resource.getRequestPath());
                menuResDTO.setComponent(component + "/" + resourceResDTO.getRequestPath());

                MenuMetaResDTO menuMetaResDTO = MenuMetaResDTO.builder()
                        .icon(resourceResDTO.getIcon())
                        .title(resourceResDTO.getResourceName())
                        .build();
                menuResDTO.setMeta(menuMetaResDTO);

                menuResDTO.setRedirect("/" + resource.getResourceName() + "/" + resourceResDTO.getResourceName());

                menuResDTO.setChildren(getChildrens(resourceResDTO, resources, resource.getRequestPath()));
                childrenList.add(menuResDTO);
            }
        }

        return childrenList;
    }
}
